namespace ne   {

    interface IEvent {
        name: string,
        listener: Function,
        target: any,
        once: boolean,
    }

    class Event_ implements IEvent {
        public name: string;
        public listener: Function;
        public target: any;
        public once: boolean;
        constructor(name: string, listener: Function, target: any, once?: boolean) {
            this.name = name;
            this.listener = listener;
            this.target = target;
            this.once = once ? once : false;
        }
    }

    /** 添加事件发射器接口 */
    export interface EventDispatcher<S = {}> {
        /**
         * 监听事件
         */
        on<K extends keyof S>(name: K, listener: (evt?: S[K]) => void, target: any, once?: boolean): void;
        on(name: string | number, listener: Function, target: any, once?: boolean): void;

        /**
         * 发送事件
         */
        emit<K extends keyof S>(name: K, ...args): void;
        emit(name: string | number, ...args): boolean | void;

        /**
         * 移除事件
         */
        removeEventListener<K extends keyof S>(name: K, listener: (evt?: S[K]) => void, target: any): void;
        removeEventListener(name: string | number, listener: Function, target: any): void;
        removeEventListeners<K extends keyof S>(name: K): void;
        removeEventListeners(name: string | number): void;

        /**
         * 监听一次性事件
         */
        once<K extends keyof S>(name: K, listener: (evt?: S[K]) => void, target: any): void;
        once(name: string | number, listener: Function, target: any): void;
    }


    export class EventDispatcher {

        private _eventMap: Map<string, IEvent[]>;
        private _flag: number = 0; /**防止修改纠错flag */

        constructor() {
            this._eventMap = new Map();
        }

        public on(eventname: string | number, listencb: Function, target: any, once?: boolean): void {
            let eventMap = this._eventMap;
            if (typeof (eventname) == "number") {
                eventname = "MSG_" + eventname
            }
            let name = eventname;
            let list: Event_[] = eventMap[name];
            if (!list) {
                list = eventMap[name] = [];
            } else if (this._flag !== 0) {
                eventMap[name] = list = list.concat();
            }
            this.insertEvent(list, name, listencb, target, once);
        }

        private insertEvent(list: Event_[], name: string, listener: Function, target: any, once?: boolean) {
            let length = list.length;
            for (let i = 0; i < length; i++) {
                let event = list[i];
                if (event.listener == listener && event.target == target) {
                    return false;
                }
            }
            let event = new Event_(name, listener, target, once);
            list.push(event)
        }

        public emit(eventname: string | number, ...args) {
            if (typeof (eventname) == "number") {
                eventname = "MSG_" + eventname
            }
            let eventMap = this._eventMap;
            let name = eventname;
            let list: Event_[] = eventMap[name];
            if (!list) {
                return true;
            }
            let length = list.length;
            if (length == 0) {
                return true;
            }
            let onceList: Event_[] = [];
            this._flag++;
            for (let i = 0; i < length; i++) {
                let event = list[i];
                event.listener.call(event.target, ...args);
                if (event.once) {
                    onceList.push(event);
                }
            }
            this._flag--;
            while (onceList.length) {
                let event = onceList.pop();
                this.removeEventListener(event.name, event.listener, event.target);
            }
        }

        public removeEventListener(name: string | number, listener: Function, target: any): void {
            if (typeof (name) == "number") {
                name = "MSG_" + name
            }
            let eventMap = this._eventMap;
            let list: Event_[] = eventMap[name];
            if (!list) {
                return;
            }
            if (this._flag !== 0) {
                eventMap[name] = list = list.concat();
            }
            this.removeEvent(list, listener, target);
            if (list.length == 0) {
                eventMap[name] = null;
            }
        }

        public removeEventListeners(name: string | number): void {
            if (typeof (name) == "number") {
                name = "MSG_" + name
            }
            let eventMap = this._eventMap;
            let list: Event_[] = eventMap[name];
            if (!list) {
                return;
            }
            list.length = 0;
            eventMap.delete(name);
        }

        private removeEvent(list: any[], listener: Function, target: any): boolean {
            let length = list.length;
            for (let i = 0; i < length; i++) {
                let event = list[i];
                if (event.listener == listener && event.target == target) {
                    list.splice(i, 1);
                    return true;
                }
            }
            return false;
        }

        public once(eventname: string | number, listencb: Function, target: any): void {
            this.on(eventname, listencb, target, true);
        }

        public dump() {
            let eventMap = this._eventMap;
            for (let name in eventMap) {
                console.log(eventMap[name]);
            }
        }
    }
}